package com.fm.mediasoup;

import android.content.Context;
import android.util.Log;


import com.fm.mediasoup.callback.CallbackMediaStream;
import com.fm.mediasoup.callback.CallbackSdp;
import com.fm.mediasoup.callback.TrackCallback;
import com.fm.mediasoup.message.SdpMessage;
import com.fm.mediasoup.util.Camera;

import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.Camera2Enumerator;
import org.webrtc.DataChannel;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.MediaStreamTrack;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionDependencies;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RtpSender;
import org.webrtc.SdpObserver;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoSink;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;
import org.webrtc.audio.JavaAudioDeviceModule;

import java.util.ArrayList;
import java.util.List;

public class Webrtc implements PeerConnection.Observer, SdpObserver {

    private final static String TAG = Webrtc.class.getSimpleName();
    private int width = 480;
    private int height = 320;
    private int fps = 30;
    private Context context;

    public void setTrackCallback(TrackCallback trackCallback) {
        this.trackCallback = trackCallback;
    }

    private TrackCallback trackCallback;
    private PeerConnectionFactory peerConnectionFactory; //peer 构造工厂
    private PeerConnection peerConnection; // peer 对象
    private ArrayList<org.webrtc.PeerConnection.IceServer> iceServerList = new ArrayList<>(); // iceServer mediasoup 暂时不需要使用
    private JavaAudioDeviceModule audioDeviceModule; // 音频对象
    private PeerConnection.RTCConfiguration rtcConfig; // rtc 配置类
    private List<String> streamList;
    private PeerConnectionFactory.InitializationOptions initializationOptions;
    private EglBase.Context eglBaseContext; //渲染上下文
    private VideoCapturer videoCapturer; //视频录制
    private VideoSource videoSource; //视频资源
    private AudioSource audioSource;
    private VideoTrack videoTrack;
    private AudioTrack audioTrack;
    private SurfaceTextureHelper surfaceTextureHelper;

    private String videoTrackLabel = "video";
    private String audioTrackLabel = "audio";

    private CallbackSdp callbackSdp = null; //回调sdp 信息

    public void setCallbackSdp(CallbackSdp callbackSdp) {
        this.callbackSdp = callbackSdp;
    }

    public void setCallbackMediaStream(CallbackMediaStream callbackMediaStream) {
        this.callbackMediaStream = callbackMediaStream;
    }

    private CallbackMediaStream callbackMediaStream = null;



    public Webrtc(Context context, EglBase.Context eglBaseContext, int width, int height, int fps){
        this.context = context;
        this.eglBaseContext = eglBaseContext;
        this.width = width;
        this.height = height;
        this.fps = fps;
        this.init();
    }

    public Webrtc(Context context, EglBase.Context eglBaseContext) {
        this(context, eglBaseContext, 480, 320, 15);
    }

    private void init(){
        initRtcConfig();
        initAudioDeviceModule();
        initPeerConnectionFactory();
        initPeerConnection();
        initStreamList();
    }

    private void initRtcConfig(){
        rtcConfig = new org.webrtc.PeerConnection.RTCConfiguration(iceServerList);
        rtcConfig.rtcpMuxPolicy =  PeerConnection.RtcpMuxPolicy.REQUIRE;
        rtcConfig.iceTransportsType = PeerConnection.IceTransportsType.ALL;
        rtcConfig.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE;
        rtcConfig.sdpSemantics = org.webrtc.PeerConnection.SdpSemantics.UNIFIED_PLAN;
    }

    private void initAudioDeviceModule(){
        this.audioDeviceModule = JavaAudioDeviceModule.builder(this.context).createAudioDeviceModule();
    }


    private void initPeerConnectionFactory(){
        initializationOptions = PeerConnectionFactory.InitializationOptions.builder(this.context)
                .createInitializationOptions();
        PeerConnectionFactory.initialize(initializationOptions);

        peerConnectionFactory = PeerConnectionFactory.builder()
             //   .setAudioDeviceModule(audioDeviceModule)
                .setVideoDecoderFactory(new DefaultVideoDecoderFactory(this.eglBaseContext))
                .setVideoEncoderFactory(new DefaultVideoEncoderFactory(this.eglBaseContext, true, true))
                .createPeerConnectionFactory();

    }

    private void initPeerConnection(){
        PeerConnectionDependencies peerConnectionDependencies = PeerConnectionDependencies.builder(this).createPeerConnectionDependencies();
        peerConnection = peerConnectionFactory.createPeerConnection(rtcConfig, peerConnectionDependencies);
    }

    private void initStreamList() {
        streamList = new ArrayList<>();
        streamList.add("stream");
    }

    /**
     * 停止视频推流
     */
    public void stopVideoTrack(){
        if (videoTrack != null) videoTrack.setEnabled(false);
        if (videoCapturer != null) {
            try {
                videoCapturer.stopCapture();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void startVideoTrack(){
        Log.e("fmfmfm", "width="+width+",height="+height);
        if (videoCapturer != null) videoCapturer.startCapture(width, height, fps);
        if (videoTrack != null) videoTrack.setEnabled(true);
    }


    /**
     * 重新设置宽高，由于 视频最低给出还是 176 144 
     * @param width
     * @param height
     * @param fps
     */
    public void resetVideoTrack(int width, int height, int fps){
        this.width = width;
        this.height = height;
        this.fps = fps;
        if (this.videoCapturer != null) this.videoCapturer.changeCaptureFormat(this.width, this.height, this.fps);

//        // 移除旧的视频轨道
//        if (videoCapturer != null) {
//            try {
//                videoCapturer.stopCapture();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
//
//        List<RtpSender> senders = peerConnection.getSenders();
//        for (RtpSender sender : senders) {
//            MediaStreamTrack track = sender.track();
//            if (track != null) {
//                Log.e("fmfmf", track.kind());
//            }
//            if (track != null && track.kind().equals(videoTrackLabel)) {
//            //    peerConnection.removeTrack(sender);
//                break;
//            }
//        }
//
//        videoTrack.setEnabled(false);
//        videoSource = peerConnectionFactory.createVideoSource(videoCapturer.isScreencast());
//        videoTrack = peerConnectionFactory.createVideoTrack(videoTrackLabel, videoSource);
//        videoCapturer.startCapture(this.width, this.height, this.fps);
//      //  peerConnection.addTrack(videoTrack, streamList);
//        videoTrack.setEnabled(true);

    }


    public void stopAudioTrack(){
        if (audioTrack != null) audioTrack.setEnabled(false);
    }

    public void startAudioTrack(){
        if (audioTrack != null) audioTrack.setEnabled(true);
    }

    /**
     * 添加音频轨
     */
    public void addAudioTrack(){
        audioSource = peerConnectionFactory.createAudioSource(new MediaConstraints());
        audioTrack = peerConnectionFactory.createAudioTrack(audioTrackLabel, audioSource);
        audioTrack.setEnabled(true);
        audioTrack.setVolume(500);
        if (trackCallback != null) trackCallback.audioTrack(audioTrack);
        peerConnection.addTrack(audioTrack, streamList);
    }

    /**
     * 添加视频
     */
    public void addVideoTrack(){
        videoCapturer = Camera.createCameraCapturer(new Camera2Enumerator(context));
        if (videoCapturer != null) {
            videoSource = peerConnectionFactory.createVideoSource(videoCapturer.isScreencast());
            videoTrack = peerConnectionFactory.createVideoTrack(videoTrackLabel, videoSource);
            videoTrack.setEnabled(true);
            if (trackCallback != null) trackCallback.videoTrack(videoTrack);
            peerConnection.addTrack(videoTrack, streamList);
        }
    }

    /**
     * 开启视频录制
     */
    public void startVideoCapturer(SurfaceTextureHelper surfaceTextureHelper){
        this.surfaceTextureHelper = surfaceTextureHelper;
        videoCapturer.initialize(surfaceTextureHelper, context, videoSource.getCapturerObserver());
        Log.e("fmfmfm", "width="+width+"height="+height);
        videoCapturer.startCapture(width, height, fps);
    }


    /**
     * 创建应答
     */
    public void createAnswer(){
        //initPeerConnection();
        peerConnection.createAnswer(this, new MediaConstraints());
    }

    /**
     * 创建发送 offer
     */
    public void createOffer(){
        peerConnection.createOffer(this, new MediaConstraints());
    }

    /**
     * 设置远端数据源，自己接收音视频数据
     * @param sdp
     */
    public void setOfferDescription(String sdp){
        SessionDescription sessionDescription = new SessionDescription(SessionDescription.Type.OFFER, sdp);
        Log.e("setOfferDescription", sessionDescription.description.toString());
        peerConnection.setRemoteDescription(this, sessionDescription);
    }

    /**
     * 设置远端数据源，接收本地数据
     * @param sdp
     */
    public void setAnswerDescription(String sdp){
        SessionDescription sessionDescription = new SessionDescription(SessionDescription.Type.ANSWER, sdp);
        Log.e("setAnswerDescription", sessionDescription.description.toString());
        peerConnection.setRemoteDescription(this, sessionDescription);
    }



    public void release(){
        try {
            if (peerConnection != null) {
                peerConnection.dispose();
            }
            if (videoCapturer != null)
                videoCapturer.stopCapture();

            if (audioDeviceModule != null)
                audioDeviceModule.release();

        }catch (Exception e) {
            e.printStackTrace();
        }
    }


    //Observer 数据回调
    @Override
    public void onSignalingChange(PeerConnection.SignalingState signalingState) {
        Log.e("onSignalingChange", signalingState.toString());
    }

    @Override
    public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
        Log.e("onIceConnectionChange", iceConnectionState.toString());
    }

    @Override
    public void onIceConnectionReceivingChange(boolean b) {

    }

    @Override
    public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {

    }

    @Override
    public void onIceCandidate(IceCandidate iceCandidate) {
        Log.e("onIceCandidate", iceCandidate.toString());
    }

    @Override
    public void onIceCandidatesRemoved(IceCandidate[] iceCandidates) {

    }

    @Override
    public void onAddStream(MediaStream mediaStream) {
        if (callbackMediaStream != null) callbackMediaStream.addStream(mediaStream);
    }

    @Override
    public void onRemoveStream(MediaStream mediaStream) {
        if (callbackMediaStream != null) callbackMediaStream.removeStream(mediaStream);
    }

    @Override
    public void onDataChannel(DataChannel dataChannel) {

    }

    @Override
    public void onRenegotiationNeeded() {

    }


    /**
     * sdp server 回调
     * @param sessionDescription
     */
    @Override
    public void onCreateSuccess(SessionDescription sessionDescription) {

        if (sessionDescription.type == SessionDescription.Type.OFFER) {

            SdpMessage sdpMessage = new SdpMessage("offer", sessionDescription.description);
                      peerConnection.setLocalDescription(this, sessionDescription);
            // 接收数据，先设置后调
            if (this.callbackSdp != null) this.callbackSdp.offer(sdpMessage);

        }

        if (sessionDescription.type == SessionDescription.Type.ANSWER) {
            SdpMessage sdpMessage = new SdpMessage("answer", sessionDescription.description);
            /**
             *  //answer先回调 将数据信息发送给服务端
             */
            if (this.callbackSdp != null) this.callbackSdp.answer(sdpMessage);
            peerConnection.setLocalDescription(this, sessionDescription);
        }
    }

    @Override
    public void onSetSuccess() {
        Log.e("onSetSuccess", "onSetSuccess");
    }

    @Override
    public void onCreateFailure(String s) {
        Log.e("onCreateFailure", s);
    }

    @Override
    public void onSetFailure(String s) {
        Log.e("onSetFailure", s);
    }
}
